package ClassStudy;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

/**
 * @author Cheng Jun
 * Description: 学习反射的基础方法
 * @version 1.0
 * @date 2021/8/22 10:00
 */
public class ClassBasic {

    public static void main(String[] args) throws Exception {
        String studentClassPath = "ClassStudy.Student";
        Class<?> aClass = Class.forName(studentClassPath);
        // 当前 aClass 对象，具体是哪个类的 Class对象
        System.out.println(aClass);
        // aClass 运行类型 即 java.lang.Class
        System.out.println(aClass.getClass());
        // 获取全类名，在toString 就有调用
        System.out.println(aClass.getName());
        // 获取包名. 其实还是 先调用getName ClassStudy.Student ，然后截断 .Student
        System.out.println(aClass.getPackage());
        // 通过 aClass 创建对象实例
        Object instance = aClass.newInstance();
        System.out.println(instance.toString());
        // 通过反射获取 属性，属性值，注意 getField 只能获取 public 修饰的变量。private/protected/default
        // 后面会有讲解
        Field ageField = aClass.getField("age");
        System.out.println(ageField);
        // field.get(object) 从object中提取 field的值。如果field 是static修饰，field.get(null) 即可
        System.out.println(ageField.get(instance));
        // 通过反射 修改 age的值
        ageField.set(instance, 11);
        System.out.println("修改后的值" + ageField.get(instance));
        // 获取所有 public 修饰的 Field
        Field[] fields = aClass.getFields();
        for (Field field : fields) {
            System.out.println(field);
        }
        // 获取所有 Field
        Field[] declaredFields = aClass.getDeclaredFields();
        // 修饰符值：default=0,public=1,private=2,protected=4,static=8,final=16
        for (Field declaredField : declaredFields) {
            declaredField.setAccessible(true);
            if (declaredField.getName().equals("SCHOOL")) {
                // 只有final修饰的或者只有static修饰的，都能反射直接改
                // 如果 final static 修饰的话，就不能直接该，需要先该掉 Field 类的modifiers变量的值。
                // 去除 变量的final 修饰符
                Field modifiers = Field.class.getDeclaredField("modifiers");
                modifiers.setAccessible(true);
                modifiers.setInt(declaredField, declaredField.getModifiers() & ~Modifier.FINAL);
                declaredField.set(instance, "北京大学");
            }
            System.out.println("本类中的属性 = " + declaredField.getName() +
                    "该属性的修饰符值 = " + declaredField.getModifiers() +
                    "该属性的类型 = " + declaredField.getType() +
                    "该属性的值 = " + declaredField.get(instance));
        }
        // 获取 构造器，带有 String 参数的构造器
        Constructor constructor = aClass.getConstructor(String.class);
        System.out.println(constructor);
        for (Constructor<?> aClassConstructor : aClass.getConstructors()) {
            System.out.println(aClassConstructor);
        }
        Object cauchy6317 = constructor.newInstance("Cauchy6317");
        System.out.println(cauchy6317);

        // 获取申明的构造器
        Constructor<?> declaredConstructor = aClass.getDeclaredConstructor(String.class, int.class);
        // 爆破 declaredConstructor 的私有性
        declaredConstructor.setAccessible(true);
        Object cauchy6318 = declaredConstructor.newInstance("Cauchy6318", 27);
        System.out.println(cauchy6318);

        Method chirographyMethod = aClass.getDeclaredMethod("chirography");
        chirographyMethod.setAccessible(true);
        // 如果 chirographyMethod 是类方法，则 invoke 可以传参 null，编译时统一由Object 接受，运行时具体方法的返回值类型
        Object result = chirographyMethod.invoke(cauchy6317);
        // Object result = chirographyMethod.invoke(null);
        System.out.println(result);

    }
}
